package
{
	import flash.display.Stage;
	import flash.geom.Point;

	public class TileGameHelper
	{
		public var game:ITileGame;
		
		private var m_tilesToDestroy:Vector.<Tile>;
		
		public function TileGameHelper(game:ITileGame)
		{
			this.game = game;
			m_tilesToDestroy = new Vector.<Tile>;
		}
		
		public function getTileAt(x:int, y:int):Tile
		{
			for each(var tile:Tile in game.getAllTiles())
			{
				if(tile.x == x && tile.y == y)
				{
					return tile;
				}
			}
			
			return null;
		}
		
		public function tileHitTest(x:Number, y:Number, stage:Stage):Tile
		{
			var point:Point = new Point(x,y);
			for each(var tile:Tile in game.getAllTiles())
			{
				if(tile.interactable && tile.display.getBounds(stage).containsPoint(point))
				{
					return tile;
				}
			}			
			
			return null;
		}
		
		
		
		public function getAdjacentTiles(tile:Tile):Vector.<Tile>
		{
			var adjTiles:Vector.<Tile> = new Vector.<Tile>;
			var m_allTiles:Vector.<Tile> = game.getAllTiles();
			for each(var _tile:Tile in m_allTiles)
			{
				var distance:Number = new Point(tile.x, tile.y).subtract(new Point(_tile.x, _tile.y)).length;
				if(_tile != tile && _tile.interactable && distance < 1.1)
				{
					adjTiles.push(_tile);
				}
			}
			
			return adjTiles;
		}
		
		public function disableTiles(tiles:Vector.<Tile>):void
		{
			for each(var tile:Tile in tiles)
			{
				tile.interactable = false;
			}
		}
		
		public function enableTiles(tiles:Vector.<Tile>):void
		{
			for each(var tile:Tile in tiles)
			{
				tile.interactable = true;
			}
		}		
		
		public function destroyTiles(tiles:Vector.<Tile>):void
		{
			for each(var tile:Tile in tiles)
			{
				
				if(m_tilesToDestroy.indexOf(tile) != -1)
				{
					throw new Error("Should not already be destroyed");
				}
				tile.interactable = false;
				m_tilesToDestroy.push(tile);
				tile.display.visible = false;
			}
			
				
		
		}
		
		public function getConnectedMatch3Tiles(tile:Tile,  connectedTilesResult:Vector.<Tile> = null):Vector.<Tile>
		{
			var connectedTiles:Vector.<Tile> = getConnectedTiles(tile, new Vector.<Tile>);
			if(connectedTiles.length >= 3)
			{
				var lookup:Object = new Object();
				var resultObject:Object = new Object();
				var _tile:Tile;
				for each(_tile in connectedTiles)
				{
					lookup[_tile.getStringXY()] = _tile;
				}
				
				for each(_tile in connectedTiles)
				{
					var left:Tile = lookup[String(_tile.x-1) + ',' + String(_tile.y)];
					var right:Tile = lookup[String(_tile.x+1) + ',' + String(_tile.y)];
					var above:Tile = lookup[String(_tile.x) + ',' + String(_tile.y+1)];
					var below:Tile = lookup[String(_tile.x) + ',' + String(_tile.y-1)];
					
					if(left != null && right != null)
					{
						resultObject[left.getStringXY()] = left;
						resultObject[_tile.getStringXY()] = _tile;
						resultObject[right.getStringXY()] = right;
					}
					
					if(above != null && below != null)
					{
						resultObject[above.getStringXY()] = above;
						resultObject[_tile.getStringXY()] = _tile;
						resultObject[below.getStringXY()] = below;
					}				
				}
				
				for each(_tile in resultObject)
				{
					connectedTilesResult.push(_tile);
				}
			}
			
			return connectedTilesResult;
		}
		
		public function getConnectedTiles(tile:Tile, connectedTilesResult:Vector.<Tile> = null):Vector.<Tile>
		{
			connectedTilesResult.push(tile);
			var adjTiles:Vector.<Tile> = getAdjacentTiles(tile);
			for each(var adjTile:Tile in adjTiles)
			{
				if(adjTile.getColor() == tile.getColor() && connectedTilesResult.indexOf(adjTile) == -1)
				{
					getConnectedTiles(adjTile, connectedTilesResult);
				}
			}
			
			return connectedTilesResult;
		}	
		
		public function onFrame():void
		{
			var allTiles:Vector.<Tile> = game.getAllTiles();
			
			if(m_tilesToDestroy.length > 0)
			{
				for(var i:int = m_tilesToDestroy.length-1; i >= 0; i--)
				{
					var tile:Tile = m_tilesToDestroy[i];
					tile.display.parent.removeChild(tile.display);
					allTiles.splice(allTiles.indexOf(tile),1);
				}			
				m_tilesToDestroy = new Vector.<Tile>;
				
				dropNewTiles();
			}
			
			
		}
		
		public function dropNewTiles():void
		{
			var dropGroups:Vector.<TileDropGroup> = new Vector.<TileDropGroup>;
			for(var col:int = 0; col < game.getBoardWidth(); col++)
			{
				var interactable:Boolean = true;
				var emptyLocs:Vector.<Point> = new Vector.<Point>;
				var tdg:TileDropGroup = new TileDropGroup(new Vector.<Tile>);
				tdg.dropStyle = TileDropGroup.DROP_STYLE_REPLENISH;
				for(var row:int = game.getBoardHeight()-1; row >= 0; row--)
				{
					var tile:Tile = game.getTileAt(col, row);
					if(tile == null)
					{
						interactable = false;
						emptyLocs.push(new Point(col,row));
					}
					else
					{
						if(tile.interactable)
						{
							tile.interactable = interactable;	
						}
						if(emptyLocs.length > 0)
						{
							tile.y = tile.y + emptyLocs.length;
							tdg.addTile(tile);							
						}
					}	
				}
				
				if(emptyLocs.length > 0){
					var emptyTdg:TileDropGroup = new TileDropGroup(new Vector.<Tile>);
					emptyTdg.dropStyle = TileDropGroup.DROP_STYLE_REPLENISH;
					for(var i:int = 0, il:int = emptyLocs.length; i < il; i++)
					{
						var emptyLoc:Point = emptyLocs[i];
						var newTile:Tile = game.createNewTile(emptyLoc.x, il-(i+1));
						newTile.display.y = -(i+1)*newTile.tileSize;
						newTile.display.x = emptyLoc.x*newTile.tileSize;
						emptyTdg.addTile(newTile);
						game.addTile(newTile);
						
					}
					dropGroups.push(emptyTdg);
				}				
				
				dropGroups.push(tdg);
			}
			
			for each(tdg in dropGroups)
			{
				tdg.go();
			}
		}		
	}
}